Security News
JSR Working Group Kicks Off with Ambitious Roadmap and Plans for Open Governance
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
@metamask/json-rpc-engine
Advanced tools
@metamask/json-rpc-engine is a library for creating and managing JSON-RPC middleware stacks. It is particularly useful for building JSON-RPC servers and clients, and it provides a flexible way to handle JSON-RPC requests and responses.
Creating a JSON-RPC Engine
This feature allows you to create a new JSON-RPC engine instance, which can be used to manage middleware and handle JSON-RPC requests.
const { JsonRpcEngine } = require('@metamask/json-rpc-engine');
const engine = new JsonRpcEngine();
Adding Middleware
This feature allows you to add middleware to the JSON-RPC engine. Middleware can inspect and modify requests and responses, or terminate the request handling.
engine.push((req, res, next, end) => {
if (req.method === 'test_method') {
res.result = 'test_result';
return end();
}
next();
});
Handling Requests
This feature allows you to handle JSON-RPC requests using the engine. The engine processes the request through the middleware stack and returns the response.
const request = { id: 1, jsonrpc: '2.0', method: 'test_method' };
engine.handle(request, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
Jayson is a JSON-RPC 2.0/1.0 client and server for Node.js. It provides a simple and flexible way to create JSON-RPC servers and clients, similar to @metamask/json-rpc-engine, but with a focus on ease of use and a more extensive feature set for building full-fledged JSON-RPC services.
jsonrpc-lite is a lightweight JSON-RPC 2.0 library for Node.js. It provides basic utilities for parsing and serializing JSON-RPC messages, making it a simpler alternative to @metamask/json-rpc-engine for projects that require minimal JSON-RPC functionality.
node-json-rpc is a JSON-RPC 2.0 server and client library for Node.js. It offers a straightforward way to create JSON-RPC servers and clients, similar to @metamask/json-rpc-engine, but with a focus on simplicity and ease of integration.
@metamask/json-rpc-engine
A tool for processing JSON-RPC requests and responses.
yarn add @metamask/json-rpc-engine
or
npm install @metamask/json-rpc-engine
const { JsonRpcEngine } = require('@metamask/json-rpc-engine');
const engine = new JsonRpcEngine();
Build a stack of JSON-RPC processors by pushing middleware to the engine.
engine.push(function (req, res, next, end) {
res.result = 42;
end();
});
Requests are handled asynchronously, stepping down the stack until complete.
const request = { id: 1, jsonrpc: '2.0', method: 'hello' };
engine.handle(request, function (err, response) {
// Do something with response.result, or handle response.error
});
// There is also a Promise signature
const response = await engine.handle(request);
Middleware have direct access to the request and response objects.
They can let processing continue down the stack with next()
, or complete the request with end()
.
engine.push(function (req, res, next, end) {
if (req.skipCache) return next();
res.result = getResultFromCache(req);
end();
});
By passing a return handler to the next
function, you can get a peek at the result before it returns.
engine.push(function (req, res, next, end) {
next(function (cb) {
insertIntoCache(res, cb);
});
});
If you specify a notificationHandler
when constructing the engine, JSON-RPC notifications passed to handle()
will be handed off directly to this function without touching the middleware stack:
const engine = new JsonRpcEngine({ notificationHandler });
// A notification is defined as a JSON-RPC request without an `id` property.
const notification = { jsonrpc: '2.0', method: 'hello' };
const response = await engine.handle(notification);
console.log(typeof response); // 'undefined'
Engines can be nested by converting them to middleware using JsonRpcEngine.asMiddleware()
:
const engine = new JsonRpcEngine();
const subengine = new JsonRpcEngine();
engine.push(subengine.asMiddleware());
async
MiddlewareIf you require your middleware function to be async
, use createAsyncMiddleware
:
const { createAsyncMiddleware } = require('@metamask/json-rpc-engine');
let engine = new RpcEngine();
engine.push(
createAsyncMiddleware(async (req, res, next) => {
res.result = 42;
next();
}),
);
async
middleware do not take an end
callback.
Instead, the request ends if the middleware returns without calling next()
:
engine.push(
createAsyncMiddleware(async (req, res, next) => {
res.result = 42;
/* The request will end when this returns */
}),
);
The next
callback of async
middleware also don't take return handlers.
Instead, you can await next()
.
When the execution of the middleware resumes, you can work with the response again.
engine.push(
createAsyncMiddleware(async (req, res, next) => {
res.result = 42;
await next();
/* Your return handler logic goes here */
addToMetrics(res);
}),
);
You can freely mix callback-based and async
middleware:
engine.push(function (req, res, next, end) {
if (!isCached(req)) {
return next((cb) => {
insertIntoCache(res, cb);
});
}
res.result = getResultFromCache(req);
end();
});
engine.push(
createAsyncMiddleware(async (req, res, next) => {
res.result = 42;
await next();
addToMetrics(res);
}),
);
If your middleware has teardown to perform, you can assign a method destroy()
to your middleware function(s),
and calling JsonRpcEngine.destroy()
will call this method on each middleware that has it.
A destroyed engine can no longer be used.
const middleware = (req, res, next, end) => {
/* do something */
};
middleware.destroy = () => {
/* perform teardown */
};
const engine = new JsonRpcEngine();
engine.push(middleware);
/* perform work */
// This will call middleware.destroy() and destroy the engine itself.
engine.destroy();
// Calling any public method on the middleware other than `destroy()` itself
// will throw an error.
engine.handle(req);
Handle errors via end(err)
, NOT next(err)
.
/* INCORRECT */
engine.push(function (req, res, next, end) {
next(new Error());
});
/* CORRECT */
engine.push(function (req, res, next, end) {
end(new Error());
});
However, next()
will detect errors on the response object, and cause
end(res.error)
to be called.
engine.push(function (req, res, next, end) {
res.error = new Error();
next(); /* This will cause end(res.error) to be called. */
});
This package is part of a monorepo. Instructions for contributing can be found in the monorepo README.
FAQs
A tool for processing JSON-RPC messages
We found that @metamask/json-rpc-engine demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 11 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
Security News
Research
An advanced npm supply chain attack is leveraging Ethereum smart contracts for decentralized, persistent malware control, evading traditional defenses.
Security News
Research
Attackers are impersonating Sindre Sorhus on npm with a fake 'chalk-node' package containing a malicious backdoor to compromise developers' projects.